Skip to content

feat(linux): fcitx5 plugin for Wayland input + deb packaging#451

Open
aeoform wants to merge 15 commits into
Open-Less:betafrom
aeoform:beta
Open

feat(linux): fcitx5 plugin for Wayland input + deb packaging#451
aeoform wants to merge 15 commits into
Open-Less:betafrom
aeoform:beta

Conversation

@aeoform
Copy link
Copy Markdown

@aeoform aeoform commented May 15, 2026

User description

Summary

  • fcitx5 C++ plugin (scripts/linux-fcitx5-plugin/): DBus interface with CommitText, SetHotkey/SetHotkeyRaw/SetQaHotkeyRaw/SetTranslationHotkeyRaw methods and DictationKeyEvent/QaShortcutEvent/TranslationModifierEvent signals. Replaces enigo/XTest for Wayland and X11 compatibility.
  • Fix: QA panel + translation modifier hotkeys: Added SetQaHotkeyRaw/SetTranslationHotkeyRaw DBus methods, QaShortcutEvent/TranslationModifierEvent signals. PlaceholderAdapter::update_modifier_shortcuts now syncs QA and translation triggers to the plugin via DBus. Built-in Shift key translation modifier also detected by the plugin.
  • linux_fcitx.rs: DBus client connecting Rust backend to the plugin. start_dictation_signal_listener now listens for all OpenLess1 signals (DictationKeyEvent / QaShortcutEvent / TranslationModifierEvent).
  • Wayland + X11 unified on fcitx5: Removed all is_wayland_session() distinctions. Linux uses fcitx5 plugin for hotkey source and text commit on both Wayland and X11.
  • Capsule window removed from Linux: emit_capsule skips all window operations on Linux. Target app always holds keyboard focus.
  • Deleted ~290 lines of dead rdev code: Linux hotkey platform module no longer contains rdev::listen, dispatch_event, trigger_to_rdev_key, or 10 test functions. rdev dependency removed from Cargo.toml.
  • Frontend/backend cleanup: Removed WaylandHotkeyCallout component, is_wayland_session function, wayland_cli_mode IPC, wayland sections from 5 i18n files.
  • DBus injection note: CommitText on the session bus is open to all same-user processes. This matches fcitx5/IBus standard security model, documented in plugin header comment.

Test plan

  • Linux/Wayland: dictation text inserted via fcitx5 plugin, capsule window does not appear
  • Linux/X11: dictation text inserted via fcitx5 plugin, capsule window does not appear
  • Linux: QA panel hotkey works, translation modifier hotkey works
  • macOS/Windows CI: cargo check passes (cfg gate verified)
  • Linux cargo check + unit tests: pass
  • deb install: /usr/lib/fcitx5/libopenless.so exists
  • fcitx5 restart: fcitx5 -rd shows no errors

PR Type

Enhancement, Bug fix


Description

  • Add Linux fcitx5 DBus plugin

    • Commit text and emit hotkey signals
    • Sync dictation, QA, translation triggers
  • Prefer plugin commits over Linux fallback

  • Remove Wayland-only hotkey and capsule paths

  • Update packaging, UI, and locales


Diagram Walkthrough

flowchart LR
  UI["Frontend settings and locale updates"] -- "configure" --> CORE["Rust coordinator and insertion flow"]
  CORE -- "DBus bridge" --> FCITX["linux_fcitx client"]
  FCITX -- "CommitText / signals" --> PLUGIN["fcitx5 OpenLess addon"]
  RELEASE["Release packaging"] -- "bundles" --> PLUGIN
Loading

File Walkthrough

Relevant files
Enhancement
14 files
hotkey.rs
Switch Linux hotkeys to fcitx5 adapter                                     
+20/-378
linux_fcitx.rs
Add DBus client and signal bridge                                               
+305/-0 
coordinator.rs
Sync Linux bindings and launch listener                                   
+88/-8   
unicode_keystroke.rs
Commit Linux text through fcitx5                                                 
+10/-27 
types.rs
Rename hotkey adapter to fcitx5                                                   
+5/-5     
Settings.tsx
Remove Wayland-only hotkey callout                                             
+1/-186 
ja.ts
Update Japanese Linux hotkey labels                                           
+2/-20   
zh-TW.ts
Update Traditional Chinese Linux labels                                   
+2/-20   
ko.ts
Update Korean Linux hotkey labels                                               
+2/-20   
zh-CN.ts
Update Simplified Chinese Linux labels                                     
+2/-20   
en.ts
Update English Linux hotkey labels                                             
+2/-20   
PermissionsSection.tsx
Show fcitx5 adapter name                                                                 
+1/-1     
types.ts
Rename frontend adapter type                                                         
+1/-1     
openless.cpp
Implement fcitx5 OpenLess addon                                                   
+432/-0 
Bug fix
2 files
dictation.rs
Drop Wayland gating from insert flow                                         
+24/-90 
insertion.rs
Prefer fcitx5 commit before fallback                                         
+15/-0   
Configuration changes
5 files
lib.rs
Gate Linux module registration                                                     
+3/-10   
build.sh
Add plugin build helper script                                                     
+29/-0   
release-tauri.yml
Bundle fcitx5 plugin into releases                                             
+62/-6   
CMakeLists.txt
Add fcitx5 plugin build targets                                                   
+45/-0   
openless.conf.in
Define fcitx5 addon metadata                                                         
+15/-0   
Documentation
3 files
selection.rs
Simplify Linux selection platform notes                                   
+1/-1     
cli.rs
Rewrite Linux trigger path documentation                                 
+1/-4     
AdvancedSection.tsx
Revise Linux streaming insertion hint                                       
+1/-1     
Dependencies
1 files
Cargo.toml
Add Linux DBus dependency                                                               
+2/-1     
Miscellaneous
2 files
commands.rs
Clean up obsolete Linux command exports                                   
+0/-12   
ipc.ts
Remove stale Wayland IPC helpers                                                 
+0/-6     

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 2026

PR Reviewer Guide 🔍

(Review updated until commit f043176)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Foreground check bypass

On Linux this branch now always calls insert() even when focus_ready_for_paste is false. If dictation finishes after the user switches windows, commit_text() will submit into whichever input context is currently active instead of falling back to copy-only, so text can end up in the wrong app.

#[cfg(target_os = "linux")]
{
    // Linux: fcitx5 commitString 无需窗口焦点,始终尝试插入。
    inner
        .inserter
        .insert(&polished, restore_clipboard, paste_shortcut)
}
#[cfg(not(target_os = "linux"))]
{
    log::warn!(
        "[coord] original insertion target is not foreground; copied output without paste"
    );
    if allow_non_tsf_insertion_fallback {
        inner.inserter.copy_fallback(&polished)
    } else {
        InsertStatus::Failed
    }

@aeoform
Copy link
Copy Markdown
Author

aeoform commented May 15, 2026

已修复 stale sync 问题:

ensure_modifier_hotkey_monitor 在 monitor 已存在、仅更新 binding 时,现在也会同步到 fcitx5 插件(sync_binding_to_plugin),确保设置里改热键后插件和 coordinator 热键一致。

其他两个 review 点:

  • DBus 安全 — session bus 本身有用户隔离,与 fcitx5 其他插件的安全模型一致。后续可加 sender PID 验证。
  • Linux fallback — 已删除 enigo/XTest,因为 Wayland 不支持,而 X11 用户有 fcitx5 插件(必装)。不插件的 Linux 流式输入会显示错误,非流式路径仍有剪贴板兜底。

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 265babd

@aeoform
Copy link
Copy Markdown
Author

aeoform commented May 15, 2026

后续我会考虑加上其他的输入法版本。

@aeoform
Copy link
Copy Markdown
Author

aeoform commented May 15, 2026

已修复安装路径问题:cmake 运行时通过 FCITX_INSTALL_ADDONDIR 探测当前 distro 的实际插件目录(multiarch 感知),通过 $GITHUB_ENV 传递给 tauri --config JSON。

关于 savedIc_ 野指针

  • 事件处理(hotkey)和 DBus 处理(commitText)都在 fcitx5 主事件循环同线程执行,无并发问题
  • 听写会话通常很短(几个秒),用户在这期间不太可能切换/关闭目标 app
  • InputContext 在被激活使用时不会被 fcitx5 销毁
  • foreachFocused 兜底处理了 savedIc_ 为空的情况
  • 后续可以通过 InputContext 的生命周期信号(如 destroyed)加弱引用追踪器

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit e7cfc14

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 9e81339

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 1802ed7

@aeoform
Copy link
Copy Markdown
Author

aeoform commented May 15, 2026

Linux 统一走 fcitx5 输入法的决策说明

最新提交(dce03b6)移除了 Linux 上的 enigo XTest 路径,X11 也和 Wayland 一样统一走 fcitx5 插件 CommitText 直写。

原因:

  • enigo XTest 在 Wayland 完全不可用,而 X11 上 fcitx5 也一样能用
  • XTest 合成键盘事件在不同输入法栈(ibus / fcitx5 / 无输入法)下行为不一致,容易出现"打了字母但输入法吞掉"、"中英文状态不对"等奇怪问题
  • fcitx5 CommitText 是输入法原生提交接口,直接送字上屏,不受当前输入法状态影响,也不会触发候选框
  • 维护一条路径比两条路径省心,出问题只需排查 fcitx5 插件(C++ DBus)和 Rust DBus 客户端

降级保障:

  • fcitx5 插件不可用时(fcitx5 未运行或插件未加载),自动降级到剪贴板拷贝,用户手动粘贴
  • deb 包的 Depends 已包含 fcitx5 + fcitx5-module-dbus,apt 安装时自动装上

AppImage:

  • AppImage 产物不含 fcitx5 插件(无法安装系统路径),用户需确保系统已装 fcitx5

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit dce03b6

aeoform and others added 9 commits May 16, 2026 08:53
- fcitx5 C++ plugin (scripts/linux-fcitx5-plugin/) with DBus interface:
  CommitText, SetHotkey/SetHotkeyRaw, DictationKeyEvent signal
- linux_fcitx.rs: DBus client to call plugin from Rust
- coordinator/dictation.rs: Wayland insertion via fcitx5 commit_text,
  streaming insert enabled on Wayland
- insertion.rs: fcitx5 commit_text on Linux with clipboard fallback
- unicode_keystroke.rs: Linux path uses fcitx5 commit_text
- Capsule window show-once on Linux to avoid stealing focus

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add #[cfg(target_os = "linux")] to mod linux_fcitx to fix macOS/Windows
  CI compilation (dbus crate is Linux-only).
- Wayland: skip capsule window show/hide entirely in emit_capsule so the
  target app never loses keyboard focus. Text is committed via fcitx5
  plugin commit_string — no window means the compositor forwards the
  commit to the right app.
- X11 keeps existing behavior (show capsule window once per session).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add "Build fcitx5 plugin" step to release-tauri.yml: compiles
  the C++ plugin via cmake, copies .so + .conf to
  src-tauri/linux-fcitx5-plugin/ for the Tauri bundler.
- Override tauri build --config to include deb.files / rpm.files
  that place the plugin at /usr/lib/fcitx5/ so it's auto-detected
  after install.
- Add fcitx5, fcitx5-module-dbus as deb/rpm dependencies.
- Local builds unaffected (config is CI-only via --config flag).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When ensure_modifier_hotkey_monitor finds an existing monitor and
updates the rdev/CGEventTap binding, it must also sync the new binding
to the fcitx5 plugin on Wayland. Previously the early return skipped
this, leaving plugin and coordinator out of sync after a hotkey change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
FCITX_INSTALL_ADDONDIR varies by distro (multiarch Ubuntu →
/usr/lib/x86_64-linux-gnu/fcitx5/; Fedora → /usr/lib64/fcitx5/;
Arch → /usr/lib/fcitx5/). Extract from cmake cache at build time
via GITHUB_ENV instead of hardcoding.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Prevents savedIc_ from becoming a dangling pointer by connecting to the
InputContext::destroyed signal when the IC is saved. On destruction the
pointer is cleared automatically, and commitText falls through to
foreachFocused for the current focused IC.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…syntax

ic->connect(ic->destroyed, ...) is invalid — InputContext has no two-arg
connect overload. Use ic->destroyed.connect(callback) directly, which
calls Signal<void()>::connect. Also simplified ScopedConnection storage
from unique_ptr to direct member (ScopedConnection is move-assignable).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
fcitx5 插件 Wayland/X11 都可使用,不再为 X11 单独维护 enigo XTest。
Linux 统一走 fcitx5 CommitText 直写,插件不可用时降级到剪贴板拷贝。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove 290 lines of unused rdev listener code from the Linux hotkey
platform module, drop the rdev dependency from Cargo.toml, and clean up
capsule_window_visible init leftover. Update doc comments and frontend
i18n to reflect the unified fcitx5-only path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit b349a4d

…plugin

Extend the fcitx5 plugin with SetQaHotkeyRaw/SetTranslationHotkeyRaw
DBus methods and corresponding signals, so that QA panel toggle and
translation modifier hotkeys work on Linux (not just the main dictation
hotkey). Built-in Shift key translation modifier also handled by the
plugin. Document DBus security model in plugin header.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 323dbed

@H-Chris233 H-Chris233 self-assigned this May 16, 2026
- Add SetCustomDictationTrigger(s) to plugin for custom key combos
- Add fcitx5 availability check before hotkey install, surface error
- Sync custom dictation combo to fcitx5 plugin from coordinator

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aeoform aeoform changed the title feat(linux): fcitx5 plugin for Wayland input + deb packaging feat(linux): fcitx5 plugin for Wayland/X11, fix QA/translation hotkeys, surface fcitx5 errors May 16, 2026
@github-actions github-actions Bot changed the title feat(linux): fcitx5 plugin for Wayland/X11, fix QA/translation hotkeys, surface fcitx5 errors feat(linux): fcitx5 plugin for Wayland input + deb packaging May 16, 2026
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 60250c8

Map Debian multiarch addon dir to /usr/lib64 for RPM packages.
Uses FCITX_RPM_ADDON_DIR derived from cmake output instead of
hardcoded paths.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 088e2ab

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 47f2f7b

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 416da60

…om combo and preset modifier

setHotkey/setHotkeyRaw now clear hasCustomDictationKey_ to prevent stale custom
combo from persisting after switching to a preset modifier. setCustomDictationTrigger
now persists TriggerRawSym=TriggerRawStates=0 to raw config so the old raw
trigger doesn't reload after fcitx5 restart.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 9cd8b9a

@aeoform
Copy link
Copy Markdown
Author

aeoform commented May 16, 2026

我这里没有Fn键,我不能确定是否有问题,需要有人帮忙测试一下

Fn key does not generate a standard X11 keysym on Linux. The previous
mapping to Super_L (0xffeb) was incorrect and would bind the
Windows/Super key instead. Map to RightControl (0xffe4) to match the
existing fallback convention used on Windows (VK_RCONTROL) and in the
coordinator's hotkey matching logic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@aeoform
Copy link
Copy Markdown
Author

aeoform commented May 16, 2026

已修复:HotkeyTrigger::Fn → Super_L 映射问题。

  • Fn 键在 Linux 上没有标准 X11 keysym,原来映射到 Super_L (0xffeb) 是错误的,实际绑定的是 Windows/Super 键
  • 改为 Control_R (0xffe4),与 Windows 平台 VK_RCONTROL 回退策略一致,也和 coordinator 中 Fn => ControlRight 的 keymatching 逻辑保持一致
  • macOS 平台不受影响(不经过这套代码,用 native CGEventTap key code 63)

commit: f043176

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit f043176

@aeoform
Copy link
Copy Markdown
Author

aeoform commented May 16, 2026

我不认为这是bug,用户应该在输入时自行把光标放在准备输入的位置

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants